"""
cdn.net_requests

Provides the CDN server-server communication API.

Every function here
  - has parameters (destination_server, *args)
  - returns None on failure (maybe more specific information later)
  - with name <func> sends a request which should be handled by
    cdn.server_api.<func>_handler
    
Note: For security purposes, server-side exceptions should never be thrown directly back to the client.
      Instead, only transmit back relevant information, like ie the exception message.
"""

### SPECIAL FUNCTION BELOW

"""
@note: There is no handler for this function. This function does not interact with a chord or cdn server,
       but rather with whatever server (ie lighttpd) is serving the static content.
"""
import jackson.extjson.ext_json as json
import urllib2, urllib
from django.conf import settings

from jackson import debug

def download_content(url,filename):
    """ Downloads the file at the specified URL, writes to disk
    @author: rk
    @param url: URL where the desired content can be found.
    @rtype: a Django File object or an error string (maybe an exception if you like) 
    """    
    context = [__name__, 'download_content()']
    debug.enter(context, None)
    try:
        f = urllib2.urlopen(url)
        dst_file = open(filename,'w')
        dst_file.writelines(f.readlines())
        dst_file.close()
        debug.comment(context, 'file_written_to' + str(filename))
        a = True
    except:
        a = False
        debug.exception(context,"problem downloading content")
    debug.leave(context,None)
    return a

### SPECIAL FUNCTION ABOVE

def confirm_distribution(dest, key):
    """ Ask dest whether it has a good copy of the content associated with key.
    @author: rk
    @rtype: True or False
    @todo: implement
    """
    context = [__name__, 'confirm_distributon()']
    debug.enter(context, { 'dest': dest, 'key': key })
    try:
        json_data = json.dumps(key)
        debug.comment(context, "sending request...")
        f = urllib2.urlopen('http://' + str(dest.ip) + ":" + str(dest.port) + "/cdn/confirm_distribution", urllib.urlencode({'data':json_data}))
        debug.comment(context, "received response")
        assert f.info().gettype() == 'application/json'
        response = json.loads(f.read())
        debug.comment(context, "response was " + str(response))
        debug.leave(context, { 'success?': response })
        return response
    except Exception, e:
        debug.exception(context, str(e))
        print "cdn.net.confirm_distribution(): error was:",e
        debug.leave(context, { 'exception': e })
        return False

def delegate_keys(dest, d):
    """ Informs server dest to expect keys in dictionary from servers indicated by the value d[key].
    @author: rk
    @param d: a dictionary; keys are chord keys (32-char hex strings); values are chord.Server objects
    @rtype: True on success, None on failure
    @todo: implement 
    """
    context = [__name__, 'delegate_keys()']
    debug.enter(context, None)
    try:
        json_data = json.dumps(d)
        debug.comment(context,"telling server on port " + str(dest.port) + " to take some keys")
        addr = 'http://' + str(dest.ip) + ":" + str(dest.port) + "/cdn/delegate_keys"
        debug.comment(context,"here's the message address: " + str(addr))
        f = urllib2.urlopen(addr,
                            urllib.urlencode({'data':json_data}))
        assert f.info().gettype() == 'application/json'
        r = json.loads(f.read())
        ans = r # should be true or false
        debug.comment(context, "the server we are delegating to says:" + str(ans))
        debug.comment(context, "number of keys we tried to send:" + str(len(d.keys())))
        if len(d.keys()) == ans['number_keys_transferred']:
            debug.leave(context, {"success?": True})
        else:
            debug.leave(context, {"success?": False})
        return ans
    except Exception, e:
        debug.exception(context, "(netrequests) delegate_keys() exception" + str(e))
        debug.leave(context,None)
        return False

def get_url(dest, key):
    """ Issues a get_url request to another cdn server, bypassing any client view.
    @note: this returns DNE when there is a problem, and functions depend on this 
    (get_content(), for example)
    @author: rk
    @see: jackson.cdn.client_api.get_url
    """
    context = [__name__, 'get_url()']
    debug.enter(context, None)
    try:
        json_data = json.dumps(key)
        f = urllib2.urlopen('http://' + str(dest.ip) + ":" + str(dest.port) + "/cdn/client/get_url",
                            urllib.urlencode({'data':json_data}))
        assert f.info().gettype() == 'application/json'
        r = json.loads(f.read())
        debug.leave(context, None)
        return r
    except Exception, e:
        print "cdn.net.get_url(): problem: error was:",e
        debug.leave(context, None)
        return str(e)


def is_hosting(dest, key):
    """ Asks dest whether it has the file specified by key.
    @author: rk
    @param key: key of desired file to check for
    @rtype: True or False
    @todo: implement
    """
    try:
        json_data = json.dumps(key)
        f = urllib2.urlopen('http://' + str(dest.ip) + ":" + str(dest.port) + "/cdn/is_hosting",
                            urllib.urlencode({'data':json_data}))
        assert f.info().gettype() == 'application/json'
        r = json.loads(f.read()) # should be true or false
        return r
    except Exception, e:
        print "cdn.net.is_hosting(): problem: error was:",e
        return False

def poke(dest, key):
    """ Ask dest to download key.
    @author: rk
    @rtype: None if request fails, True otherwise
    """
    try:
        json_data = json.dumps(key)
        f = urllib2.urlopen('http://' + str(dest.ip) + ":" + str(dest.port) + "/cdn/sync/poke",
                            urllib.urlencode({'data':json_data}))
        assert f.info().gettype() == 'application/json'
        r = json.loads(f.read()) # should be true or false
        return r
    except Exception, e:
        print "cdn.net.poke(): problem: error was:",e
        return False

def redirect_key(dest, key, server):
    """ Instructs dest to redirect its outgoing content associated with key to server.
    @author: rk
    @param key: key specifying content to redirect
    @param server: server to which to redirect content
    @rtype: True on success, None on failure
    @todo: implement
    """
    try:
        json_data = json.dumps({'key':key,'server':server})
        f = urllib2.urlopen('http://' + str(dest.ip) + ":" + str(dest.port) + "/cdn/redirect_key",
                            urllib.urlencode({'data':json_data}))
        assert f.info().gettype() == 'application/json'
        r = json.loads(f.read()) # should be true or false
        return r
    except Exception, e:
        print "cdn.net.redirect_key(): problem: error was:",e
        return False

